home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 40
/
Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso
/
Aminet
/
util
/
cdity
/
MRQ.lha
/
MRQ
/
Source
/
Requesters.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-10-16
|
29KB
|
982 lines
/* Requesters.c
** This is where the real work is done!
** - Functions patched into intuition and reqtools.library
** - Functions to build a MUI requester according to an
** MRQReqMessage structure
** - Message handling
**
** ©1997-2000 by Matthias.Bethke <Matthias.Bethke@gmx.net>
** You are free to modify this source or use parts of it in your
** own programs as long as they are distributed as freeware.
*/
/* $Id: Requesters.c 1.4 2000/10/15 18:06:08 msbethke Exp msbethke $
**
** $Log: Requesters.c $
** Revision 1.4 2000/10/15 18:06:08 msbethke
** Structured the button generation part a little better
** (actually this should have long gone into a MUI class of its own :-( )
** Now uses my own reentrant strtok()-function, not yet everywhere though.
**
** Revision 1.3 2000/03/30 23:18:43 msbethke
** Changed NewImage.mcc -> Guigfx.mcc
**
** Revision 1.2 2000/01/25 17:30:22 msbethke
** Adapted to new header names
** Fixed obsolete NewImage.mcc tag names/structures
**
** Revision 1.1 2000/01/25 16:57:49 msbethke
** Initial revision
**
*/
#include <proto/utility.h>
#include <exec/memory.h>
#include <exec/alerts.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/reqtools.h>
#include <lib/mb_utils.h>
#include <MUI/Guigfx_mcc.h>
#include <MUI/TransferAnim_mcc.h>
#include <math.h>
#include <ctype.h>
#include "muistuff.h"
#include "mrq.h"
#include "config.h"
#include "gfxfiles.h"
#include "MRQasm.h"
#include "mui_macros.h"
/************************************************************************/
/* local protos */
/************************************************************************/
static struct MRQReqMessage *CreateMsgAndPort(ULONG);
static STRPTR GetCallingProgram(APTR);
static void FreeMsgAndPort(struct MRQReqMessage*);
static BOOL CheckAvoidTask(struct Task*);
static STRPTR FormatButtonText(STRPTR, APTR);
static struct MRQEventClass *AnalyzeReqText(STRPTR,STRPTR);
static APTR CreateMRQButton(STRPTR, BOOL, BOOL, struct Screen*, UBYTE, BOOL);
static APTR CreateImageButton(STRPTR,struct MRQImageButton*, struct Screen*, UBYTE, BOOL);
static APTR CreateTextButton(STRPTR, UBYTE, BOOL);
static WORD PreParseButtonText(STRPTR, UBYTE, BOOL, STRPTR*, STRPTR*);
/*****************************************************************************/
#define GADBUFSIZE (256)
/*****************************************************************************/
LONG __asm __saveds EasyRequestArgsPatch(
register __a0 struct Window *ParentWindow,
register __a1 struct EasyStruct *es,
register __a2 ULONG *IDCMPptr,
register __a3 APTR ArgList)
{
static const struct EasyStruct easy = {sizeof(struct EasyStruct),0,"System error",
"EasyRequestArgs() called by %s\nwith %s == NULL!","I see"};
struct MRQReqMessage *msg;
struct Window *pwindow; // temp parent window
struct Task *MyTask;
STRPTR TaskName;
LONG RCode = -1;
MyTask = FindTask(NULL);
TaskName = MyTask->tc_Node.ln_Name ? MyTask->tc_Node.ln_Name : "<UNKNOWN>";
pwindow = ParentWindow;
// if((MyTask->tc_Node.ln_Type == NT_PROCESS) && (!pwindow))
// pwindow = ((struct Process*)MyTask)->pr_WindowPtr;
if(pwindow == (struct Window*)-1) pwindow = NULL;
prdebug("EasyRequestArgs patch entered by '%s'\n",TaskName);
if(CheckAvoidTask(MyTask) || (!AppActive))
{
return CallOldERA(ParentWindow,es,IDCMPptr,ArgList,IntuitionBase); // use standard intuition
}
if(!es->es_GadgetFormat)
{
EasyRequest(ParentWindow,(struct EasyStruct*)&easy,NULL,TaskName,"es_GadgetFormat");
return -1L;
}
if(!es->es_TextFormat)
{
EasyRequest(ParentWindow,(struct EasyStruct*)&easy,NULL,TaskName,"es_TextFormat");
return -1L;
}
if(msg = CreateMsgAndPort(IDCMPptr?*IDCMPptr:0L))
{
/* fill message structure */
msg->mrm_Easy = es;
msg->mrm_ParentWin = pwindow;
msg->mrm_ArgList = ArgList;
msg->mrm_CalledFrom = CALLER_EASYREQUESTARGS;
msg->mrm_DefaultAnswer = 1;
PutMsg(MainPort,(struct Message*)msg);
prdebug("Message sent\n");
WaitPort(msg->mrm_Message.mn_ReplyPort);
GetMsg(msg->mrm_Message.mn_ReplyPort);
prdebug("Received reply\n");
RCode = msg->mrm_RCode;
if(msg->mrm_FatalError)
{
prdebug("Fatal error in MUI requester code - using original function!\n");
RCode = CallOldERA(ParentWindow,es,IDCMPptr,ArgList,IntuitionBase);
}
FreeMsgAndPort(msg);
}
prdebug("EasyRequestArgsPatch() result: %ld\n",RCode);
return RCode;
}
/*****************************************************************************/
ULONG __asm __saveds rtEZRequestAPatch(
register __a1 char *bodyfmt,
register __a2 char *gadfmt,
register __a3 struct rtReqInfo *reqinfo,
register __a5 APTR argarray, // usually a4 - requires asm stub!!!
register __a0 struct TagItem *taglist)
{
struct MRQReqMessage *msg;
struct Window *pwindow=NULL;
struct Task *MyTask;
STRPTR TaskName;
ULONG RCode = -1;
ULONG IDCMPflags=0, IDCMPsaved=0, ReqFlags=0;
BOOL WaitPointer=FALSE, LockWindow=FALSE;
struct TagItem *tlist, *tag;
STRPTR ReqTitle=NULL;
UBYTE rtUnderscore=0, DefaultAnswer=1;
MyTask = FindTask(NULL);
TaskName = MyTask->tc_Node.ln_Name ? MyTask->tc_Node.ln_Name : "<UNKNOWN>";
if(taglist) pwindow = (struct Window*)GetTagData(RT_Window,0,taglist);
// if((MyTask->tc_Node.ln_Type == NT_PROCESS) && (!pwindow))
// pwindow = ((struct Process*)MyTask)->pr_WindowPtr;
if(pwindow == (struct Window*)-1) pwindow=NULL;
prdebug("rtEZRequestA patch entered by '%s'\n",TaskName);
/* avoid certain tasks, buttonless/asynchronous requesters, and honor AppActive */
if(CheckAvoidTask(MyTask) ||
!(AppActive && gadfmt) ||
FindTagItem(RT_ReqHandler,taglist))
{
prdebug("Requester not MUIfiable - calling original function!\n");
return CallOldrtEZRA(bodyfmt,gadfmt,reqinfo,argarray,taglist,ReqToolsBase);
}
if(!bodyfmt)
{
struct EasyStruct easy = {sizeof(struct EasyStruct),0,"MRQ error","rtEZRequestA() called by %s\nwith bodyfmt == NULL!","I see"};
EasyRequest(NULL,&easy,NULL,TaskName);
return -1L;
}
if(reqinfo)
{
ReqTitle = reqinfo->ReqTitle;
WaitPointer = reqinfo->WaitPointer;
LockWindow = reqinfo->LockWindow;
ReqFlags = reqinfo->Flags;
}
tlist = taglist;
while(tag = NextTagItem(&tlist))
{
switch(tag->ti_Tag)
{
case RT_IDCMPFlags : IDCMPflags = tag->ti_Data;
prdebug("IDCMPflags wanted: %08.lx\n",IDCMPflags);
break;
case RT_WaitPointer : WaitPointer = tag->ti_Data;
break;
case RT_LockWindow : LockWindow = tag->ti_Data;
break;
case RT_Underscore : rtUnderscore = (UBYTE)tag->ti_Data;
break;
case RTEZ_ReqTitle : ReqTitle = (STRPTR)tag->ti_Data;
break;
case RTEZ_Flags :
if(tag->ti_Data & EZREQF_CENTERTEXT) ReqFlags |= MRQMF_CENTERTEXT;
if(tag->ti_Data & EZREQF_NORETURNKEY) ReqFlags |= MRQMF_NORETURNKEY;
break;
case RTEZ_DefaultResponse : DefaultAnswer = tag->ti_Data;
break;
}
}
if(pwindow)
{
if(WaitPointer || LockWindow)
{
SetWindowPointer(pwindow,WA_BusyPointer,TRUE,TAG_DONE);
}
if(LockWindow)
{
IDCMPsaved = pwindow->IDCMPFlags;
ModifyIDCMP(pwindow,0); // turn off all IDCMP messages
}
}
if(msg = CreateMsgAndPort(IDCMPflags))
{
struct EasyStruct es = {0};
/* fake an EasyStruct :) */
es.es_TextFormat = bodyfmt;
es.es_GadgetFormat = gadfmt ? gadfmt : "OK"; // gadfmt may be NULL!
es.es_Title = ReqTitle;
/* fill message structure */
msg->mrm_Easy = &es;
msg->mrm_ArgList = argarray;
msg->mrm_CalledFrom = CALLER_RTEZREQUESTA;
msg->mrm_ParentWin = pwindow;
msg->mrm_Flags = ReqFlags;
msg->mrm_Underscore = rtUnderscore;
msg->mrm_DefaultAnswer = DefaultAnswer;
PutMsg(MainPort,(struct Message*)msg);
prdebug("Message sent\n");
WaitPort(msg->mrm_Message.mn_ReplyPort);
GetMsg(msg->mrm_Message.mn_ReplyPort);
prdebug("Received reply\n");
RCode = msg->mrm_RCode;
if(msg->mrm_FatalError)
{
prdebug("Fatal error in MUI requester code - using original function!\n");
RCode = CallOldrtEZRA(bodyfmt,gadfmt,reqinfo,argarray,taglist,ReqToolsBase);
}
FreeMsgAndPort(msg);
} else prdebug("Can't create message/port!\n");
if(pwindow)
{
if(WaitPointer || LockWindow) ClearPointer(pwindow); // reqtools compatible
if(LockWindow) ModifyIDCMP(pwindow,IDCMPsaved);
}
prdebug("rtEZRequestAPatch() result: %ld\n",RCode);
return RCode;
}
/*****************************************************************************
** GetCallingProgram() *
** Returns a pointer to the calling program's name (including directory), *
** in a newly allocted buffer. Deallocate with FreeString() (mb_utils.lib) *
** Parameters: pool : optional mempool to allocate buffer from *
******************************************************************************/
static STRPTR GetCallingProgram(APTR pool)
{
STRPTR ProgName, ProgDir, Path=NULL;
BPTR DirLock;
if(DirLock = GetProgramDir())
{
ULONG len;
ProgDir = mb_NameFromLock(pool,DirLock);
ProgName = mb_GetProgramName(pool);
if(Path=AllocVecPooled(pool,len=strlen(ProgDir)+1+strlen(ProgName)+1))
{
strcpy(Path,ProgDir);
if(!(AddPart(Path,ProgName,len)))
{
FreeVecPooled(pool,Path);
Path = NULL;
}
}
FreeString(pool,ProgDir);
FreeString(pool,ProgName);
}
return Path;
}
/*****************************************************************************
** CreateMsgAndPort() *
** Allocates a struct MRQReqMessage already filled with info common to all *
** patches. *
** Parameters: IDCMPFlags : IDCMP flags to terminate the requester *
******************************************************************************/
static struct MRQReqMessage *CreateMsgAndPort(ULONG IDCMPflags)
{
struct MRQReqMessage *msg;
/* allocate a message structure */
if(msg = AllocVec(sizeof(struct MRQReqMessage),MEMF_PUBLIC|MEMF_CLEAR)) // important for VMem systems!
{
struct MsgPort *RPort;
/* create a reply port */
if(RPort = CreateMsgPort())
{
msg->mrm_Message.mn_ReplyPort = RPort;
/* common to all patches, so let's do it here! */
msg->mrm_CallingProgram = GetCallingProgram(Config->mc_MemPool);
if(IDCMPflags)
{
struct MUI_EventHandlerNode *meh;
/* allocate an EventHandlerNode if any IDCMP bits were requested */
if(meh = AllocVec(sizeof(struct MUI_EventHandlerNode),MEMF_PUBLIC|MEMF_CLEAR))
{
meh->ehn_Priority = 0;
meh->ehn_Flags = 0;
meh->ehn_Events = IDCMPflags;
meh->ehn_Class = NULL;
msg->mrm_EventHandler = meh;
prdebug("IDCMP flags requested (0x%08.lx), eventhandler initialized\n",IDCMPflags);
} else Alert(AG_NoMemory);
}
return msg;
} else prdebug("Error creating reply port!\n");
FreeVec(msg);
} else Alert(AG_NoMemory);
return NULL;
}
/*****************************************************************************
** FreeMsgAndPort() *
** Frees a struct MRQReqMessage allocated by CreateMsgAndPort() *
******************************************************************************/
static void FreeMsgAndPort(struct MRQReqMessage *msg)
{
DeleteMsgPort(msg->mrm_Message.mn_ReplyPort);
if(msg->mrm_EventHandler) FreeVec(msg->mrm_EventHandler);
if(msg->mrm_CallingProgram) FreeString(Config->mc_MemPool,msg->mrm_CallingProgram);
FreeVec(msg);
}
/*****************************************************************************
** CheckAvoidTask() *
** Checks if the passed-in task matches the preconfigured AVOIDTASKS pattern *
** Parameters: task : task to check *
** Returns TRUE if task matches pattern *
******************************************************************************/
static BOOL CheckAvoidTask(struct Task *task)
{
if(ttVars.AvoidTasks)
{
UBYTE buf[256], *name;
name = task->tc_Node.ln_Name;
if(task->tc_Node.ln_Type == NT_PROCESS)
{
if(GetProgramName(buf,sizeof(buf)) && strlen(buf))
{
name = buf;
}
}
if(name)
{
if(MatchPattern(ttVars.AvoidTasks,name))
{
prdebug("Task name \"%s\" matches AVOIDTASKS list!\n",name);
return TRUE;
}
}
}
return FALSE;
}
/*****************************************************************************/
/************************************************************************
**
** MUI_EasyRequestArgs()
** Since MRQ V1.5 this is no longer a replacement function for
** EasyRequestArgs() but must be called by the MRQ process!
** Generalized for a couple of other requester functions, thus
** supporting features not present in EasyRequestArgs(), as of V1.7
*************************************************************************/
BOOL MUI_EasyRequestArgs(struct MRQReqMessage *msg)
{
STRPTR Title, TextFormat, GadgetFormat;
UBYTE tbuf[1024];
struct MRQEventClass *EventClass, DynEventClass;
struct MRQImage *ReqImage;
struct MUIP_Guigfx_ImageInfo IconImageInfo;
struct Screen *scr;
struct DiskObject *ProgramIcon=NULL;
APTR ButtonArgs;
BOOL IconShown=FALSE;
struct StuffCharParams StuffCharParams;
APTR Win, BtGrp, ReqImgObj;
Title = msg->mrm_Easy->es_Title;
TextFormat = msg->mrm_Easy->es_TextFormat;
GadgetFormat= msg->mrm_Easy->es_GadgetFormat;
if(ttVars.FrontmostScreen)
{
ULONG lock;
lock = LockIBase(0);
scr = ((struct IntuitionBase*)(IntuitionBase))->FirstScreen;
UnlockIBase(lock);
} else
{
if(msg->mrm_ParentWin)
{
scr = msg->mrm_ParentWin->WScreen;
} else
{
msg->mrm_ReqScreen = scr = LockPubScreen(NULL);
}
}
StuffCharParams.Position= 0;
StuffCharParams.Dest = tbuf;
StuffCharParams.DestLen = sizeof(tbuf);
ButtonArgs = RawDoFmt(TextFormat,msg->mrm_ArgList,&RDF_StuffChar,&StuffCharParams);
EventClass = AnalyzeReqText(TextFormat,tbuf);
if((EventClass == &Config->mc_DefClass) && msg->mrm_CallingProgram)
{
prdebug("default class - trying icon\n",msg->mrm_CallingProgram);
if(ProgramIcon = GetDiskObject(msg->mrm_CallingProgram))
{
prdebug("icon read\n");
if(ProgramIcon->do_Gadget.Flags & GFLG_GADGIMAGE)
{
prdebug("image gadget found\n");
memset(&DynEventClass,0,sizeof(struct MRQEventClass)); // clear
IconImageInfo.Version = GUIGFX_IMAGEINFO_VERSION;
IconImageInfo.Image = ProgramIcon->do_Gadget.GadgetRender; // enter image pointer
IconImageInfo.ColorTable = (ULONG*)MUIV_Guigfx_WBPalette; // we want a new WB-like palette
DynEventClass.mec_Image.mi_Object = &IconImageInfo;
EventClass = &DynEventClass;
IconShown = TRUE;
} else
{
prdebug("Not an image gadget!\n");
FreeDiskObject(ProgramIcon);
}
} else prdebug("Can't read icon for %s!\n",msg->mrm_CallingProgram);
}
ReqImage = msg->mrm_ReqImage = &EventClass->mec_Image;
prdebug("Final requester text: \"%s\"\nMatched for image: %s\n",
tbuf,(ReqImage->mi_Flags & MIF_FILENAME) ? ReqImage->mi_Object : (STRPTR)"<preloaded>");
if(!Title) Title = (UBYTE*)((strchr(GadgetFormat,'|'))?"Request":"Information");
if(ReqImage->mi_Flags & MIF_ANIMATION)
{
ReqImgObj = TransferAnimObject,
MUIA_TransferAnim_File, ReqImage->mi_Object,
MUIA_TransferAnim_FPS, 10,
End;
} else
{
ReqImgObj = GuigfxObject,
(ReqImage->mi_Flags & MIF_FILENAME) ?
MUIA_Guigfx_FileName :
IconShown ?
MUIA_Guigfx_ImageInfo :
MUIA_Guigfx_Picture,
ReqImage->mi_Object,
MUIA_Guigfx_ScaleMode, GGSMF_NONE,
MUIA_Guigfx_Quality, ttVars.Quality,
MUIA_Guigfx_Transparency, ttVars.Transparency ? GGTRF_MASK : 0,
End;
}
Win = MRQWindowObject,
MUIA_Window_Title, Title,
MUIA_Window_ScreenTitle, Title,
MUIA_Window_Screen, scr,
MUIA_Window_TopEdge, ttVars.MousedReq ? MUIV_Window_TopEdge_Moused : MUIV_Window_TopEdge_Centered,
MUIA_Window_LeftEdge, ttVars.MousedReq? MUIV_Window_LeftEdge_Moused: MUIV_Window_LeftEdge_Centered,
MUIA_Window_CloseGadget, FALSE,
MUIA_Window_SizeGadget, ttVars.Sizeable,
WindowContents, VGroup,
Child, HGroup,
MUIA_Frame, ttVars.SingleFrame ? MUIV_Frame_Text : MUIV_Frame_None,
Child, VGroup,
GroupSpacing(0),
MUIA_Frame, ttVars.SingleFrame ? MUIV_Frame_None : MUIV_Frame_Text,
Child, RectangleObject, End,
Child, ReqImgObj,
Child, RectangleObject, End,
End,
Child, VGroup,
GroupSpacing(0),
MUIA_Frame, ttVars.SingleFrame ? MUIV_Frame_None : MUIV_Frame_Text,
MUIA_Background, MUII_TextBack,
Child, VSpace(0),
Child, TextObject,
MUIA_Text_Contents, tbuf,
MUIA_Text_PreParse, ((!strchr(tbuf,'\n')) ||
ttVars.Centered ||
(msg->mrm_Flags & MRQMF_CENTERTEXT)) ? "\33c" : "\33l",
End,
Child, VSpace(0),
End,
End,
Child, MUI_MakeObject(MUIO_HBar,5),
Child, BtGrp = HGroup,
MUIA_Group_SameWidth, ttVars.SameWidthButtons,
MUIA_Group_SameHeight, TRUE,
End,
End,
End;
if(IconShown)
{
FreeDiskObject(ProgramIcon);
prdebug("Freed icon\n");
}
if(Win)
{
STRPTR GadgetsText;
prdebug("Created window object @$%08lx\n",Win);
msg->mrm_WindowObject = Win;
set(Win,MRQWINDOWTAG_REQMESSAGE,msg); /* keep this *before* the AddEventHandler call! */
if(msg->mrm_EventHandler)
{
msg->mrm_EventHandler->ehn_Object = Win;
DoMethod(Win,MUIM_Window_AddEventHandler,msg->mrm_EventHandler);
prdebug("IDCMP bits requested by caller: %08lx\n",msg->mrm_EventHandler->ehn_Events);
}
if(GadgetsText = FormatButtonText(GadgetFormat, ButtonArgs))
{
char *ThisButton, *NextButton=GadgetsText;
APTR TButtonP;
BOOL defaultbutton, ButtonOK=TRUE;
int i;
ThisButton = mb_strtok(&NextButton,"|");
for( i=0;
(ThisButton != NULL) && (i < MAXBUTTONS);
ThisButton = mb_strtok(&NextButton,"|"),i++)
{
/* try to create a new MUI button */
defaultbutton = (msg->mrm_DefaultAnswer==i+1) || ((NextButton==NULL) && (msg->mrm_DefaultAnswer==0));
TButtonP = CreateMRQButton(ThisButton,(i==0),(NextButton==NULL),scr,msg->mrm_Underscore,defaultbutton);
if(TButtonP)
{
DoMethod(BtGrp,OM_ADDMEMBER,TButtonP);
DoMethod(TButtonP,MUIM_Notify,MUIA_Pressed,FALSE,TButtonP,3,
MUIM_WriteLong,(NextButton||!i) ? i+1 : 0,&msg->mrm_RCode);
DoMethod(TButtonP,MUIM_Notify,MUIA_Pressed,FALSE,Application,2,
MUIM_Application_ReturnID,msg);
if(i<10)
{
ULONG fstring=MAKE_ID('f',0,0,0);
if(i==9) fstring |= MAKE_ID(0,'1','0',0);
else fstring |= (i+1+'0')<<16;
DoMethod(Win,MUIM_Notify,MUIA_Window_InputEvent,&fstring,
Win,3,MUIM_WriteLong,(NextButton||!i) ? i+1 : 0,&msg->mrm_RCode);
DoMethod(Win,MUIM_Notify,MUIA_Window_InputEvent,&fstring,
Application,2,MUIM_Application_ReturnID,msg);
}
if(defaultbutton && (!(msg->mrm_Flags & MRQMF_NORETURNKEY)))
set(Win,MUIA_Window_ActiveObject,TButtonP);
} else
{
ButtonOK = FALSE;
break;
}
}
if(ButtonOK)
{
if(EventClass->mec_RxCmdString)
{
msg->mrm_ARexxPort= EventClass->mec_RxPortName ? EventClass->mec_RxPortName : (STRPTR)"PLAY";
msg->mrm_ARexxCmd = EventClass->mec_RxCmdString;
}
DoMethod(Application,OM_ADDMEMBER,Win);
prdebug("Added window to application object\n");
DoMethod(Win,MUIM_Notify,MUIA_Window_InputEvent,"esc",
Win,3,MUIM_WriteLong,0,&msg->mrm_RCode);
DoMethod(Win,MUIM_Notify,MUIA_Window_InputEvent,"esc",
Application,2,MUIM_Application_ReturnID,msg);
DoMethod(Win,MUIM_Notify,MUIA_Window_InputEvent,"lcommand v",
Win,3,MUIM_WriteLong,1,&msg->mrm_RCode);
DoMethod(Win,MUIM_Notify,MUIA_Window_InputEvent,"lcommand v",
Application,2,MUIM_Application_ReturnID,msg);
DoMethod(Win,MUIM_Notify,MUIA_Window_InputEvent,"lcommand b",
Win,3,MUIM_WriteLong,0,&msg->mrm_RCode);
DoMethod(Win,MUIM_Notify,MUIA_Window_InputEvent,"lcommand b",
Application,2,MUIM_Application_ReturnID,msg);
set(Win,MUIA_Window_Open,TRUE);
} else
{
prdebug("Error creating button objects!\n");
msg->mrm_FatalError = TRUE;
}
FreeVec(GadgetsText);
} else
{
prdebug("Can't format gadget text!\n");
msg->mrm_FatalError = TRUE;
}
} else
{
prdebug("Can't create window object!\n");
msg->mrm_FatalError = TRUE;
}
if(!(ttVars.FrontmostScreen || msg->mrm_ParentWin)) UnlockPubScreen(NULL,scr);
return (BOOL)(!msg->mrm_FatalError);
}
static STRPTR FormatButtonText(STRPTR GadgetFormat, APTR BtArgs)
{
STRPTR tbuf;
struct StuffCharParams scp;
if(tbuf = AllocVec(GADBUFSIZE,MEMF_ANY))
{
scp.Position= 0;
scp.Dest = tbuf;
scp.DestLen = GADBUFSIZE;
RawDoFmt(GadgetFormat,BtArgs,&RDF_StuffChar,&scp);
}
return tbuf;
}
/************************************************************************
** AnalyzeReqText()
** This short piece of code is MRQ's "core", the text analyzer. It
** matches all strings in all MRQ event class structures against the
** supplied requester texts and returns a pointer to the first class that
** matches.
*************************************************************************/
static struct MRQEventClass *AnalyzeReqText(STRPTR Text, STRPTR FormattedText)
{
struct MRQEventClass *class;
struct MRQString *str;
BOOL match;
STRPTR tx;
for(class=(struct MRQEventClass*)(Config->mc_ClassList.mlh_Head);
class->mec_Node.mln_Succ;
class = (struct MRQEventClass*)(class->mec_Node.mln_Succ))
{
for(str = (struct MRQString*)(class->mec_StringList.mlh_Head);
str->ms_Node.mln_Succ;
str = (struct MRQString*)(str->ms_Node.mln_Succ))
{
tx = (str->ms_Flags & MSF_FORMATTED) ? FormattedText : Text;
if(str->ms_Flags & MSF_SUBSTRING)
{
if(str->ms_Flags & MSF_NOCASE)
match = (BOOL)mb_stristr(tx,str->ms_String);
else
match = (BOOL)strstr(tx,str->ms_String);
}
else if(str->ms_Flags & MSF_PATTERN)
{
if(str->ms_Flags & MSF_NOCASE) match = MatchPatternNoCase(str->ms_String,tx);
else match = MatchPattern(str->ms_String,tx);
}
else
{
if(str->ms_Flags & MSF_NOCASE) match = (stricmp(str->ms_String,tx) == 0);
else match = (strcmp(str->ms_String,tx) == 0);
}
if(match) return class;
}
}
return &Config->mc_DefClass;
}
/************************************************************************
** CreateMRQButton()
** The one and only button creation function, delegates work to
** CreateImageButton() and CreateTextButton().
** Parameters:
** first/last: indicate if button to make is the first or last in a
** requester
** scr : screen to remap image stuff to, if any
** uscore : character to be used as "underscore", this precedes any
** character that is to be underlined and used as a keyboard
** shortcut
** defbutton : indicates that this button is the default response button
** and its text should be printed in boldface
**
*************************************************************************/
static APTR CreateMRQButton(STRPTR text, BOOL first, BOOL last, struct Screen *scr, UBYTE uscore, BOOL defbutton)
{
STRPTR PMatchText, PParseText;
APTR ret=NULL;
UWORD cchar=0; // MUI button controlchar
if(uscore)
{
if((cchar = PreParseButtonText(text,uscore,defbutton,&PMatchText,&PParseText)) == -1) return NULL;
} else
{
PMatchText = PParseText = text;
}
/* analyze text if requested, unless button is the first one and should be marked "OK" */
if(ttVars.IButtonsByText && (!(first && ttVars.SingleIsOK)))
{
int i;
STRPTR s;
struct MRQImageButton *ibuttons[3];
UBYTE stringbuf[256];
static BOOL ButtonUsed[3];
ibuttons[0] = &Config->mc_IButton_Yes;
ibuttons[1] = &Config->mc_IButton_No;
ibuttons[2] = &Config->mc_IButton_Cancel;
if(first) ButtonUsed[0] = ButtonUsed[1] = ButtonUsed[2] = FALSE;
for(i=0; i<3; i++)
{
if(ButtonUsed[i]) continue; // don't use same button twice
mb_strlimcpy(stringbuf,ibuttons[i]->mib_Text,256);
s = strtok(stringbuf,"|");
while(s)
{
if(mb_stristr(PMatchText,s))
{
prdebug("CreateMRQButton(): matched '%s' -> button #%ld\n",s,i);
ButtonUsed[i] = TRUE;
ret = CreateImageButton(PParseText,ibuttons[i],scr,cchar,defbutton);
}
s = strtok(NULL,"|");
}
}
} else
{
if(first && Config->mc_IButton_Yes.mib_Picture)
{
ret = CreateImageButton(PParseText,&Config->mc_IButton_Yes,scr,cchar,defbutton);
} else if(last && Config->mc_IButton_No.mib_Picture)
{
ret = CreateImageButton(PParseText,&Config->mc_IButton_No,scr,cchar,defbutton);
}
}
if(!ret) ret = CreateTextButton(PParseText,cchar,defbutton);
prdebug("CreateMRQButton: button created @$%08.lx\n",ret);
if(uscore)
{
FreeVecPooled(Config->mc_MemPool,PMatchText);
FreeVecPooled(Config->mc_MemPool,PParseText);
}
set(ret,MUIA_CycleChain,1);
return ret;
}
/************************************************************************
** CreateImageButton()
** Creates a button with text an an image on the left
**
** ctlchar and defbutton: see CreateTextButton()
*************************************************************************/
static APTR CreateImageButton(STRPTR text, struct MRQImageButton *img, struct Screen *scr, UBYTE ctlchar, BOOL defbutton)
{
APTR button;
button =
VGroup,
ButtonFrame,
MUIA_InputMode, MUIV_InputMode_RelVerify,
MUIA_Background, MUII_ButtonBack,
Child, VSpace(0),
Child, HGroup,
Child, GuigfxObject,
MUIA_Guigfx_Picture, img->mib_Picture,
MUIA_Guigfx_ScaleMode, GGSMF_NONE,
MUIA_Guigfx_Quality, ttVars.Quality,
MUIA_Guigfx_Transparency, GGTRF_MASK,
End,
Child, TextObject,
MUIA_Font, MUIV_Font_Button,
MUIA_Text_Contents, text,
MUIA_Text_PreParse, (defbutton ? "\33c\33b" : "\33c"),
End,
End,
Child, VSpace(0),
End;
if(button && ctlchar)
{
set(button,MUIA_ControlChar,(LONG)ctlchar);
}
return button;
}
/************************************************************************
** CreateTextButton()
** Creates a button with only text in it.
** Optional: text rendering in boldface if defbutton is set; keyboard
** shortcut if ctlchar is set
*************************************************************************/
static APTR CreateTextButton(STRPTR text, UBYTE ctlchar, BOOL defbutton)
{
APTR button;
if(Config->mc_IButton_Yes.mib_Picture ||
Config->mc_IButton_No.mib_Picture ||
Config->mc_IButton_Cancel.mib_Picture)
{
/* use a height adaptive layout if imagebuttons are used */
button =
VGroup,
ButtonFrame,
MUIA_InputMode, MUIV_InputMode_RelVerify,
MUIA_Background, MUII_ButtonBack,
Child, VSpace(0),
Child, TextObject,
MUIA_Font, MUIV_Font_Button,
MUIA_Text_Contents, text,
MUIA_Text_PreParse, (defbutton ? "\33c\33b" : "\33c"),
End,
Child, VSpace(0),
End;
} else
{
button =
TextObject,
ButtonFrame,
MUIA_InputMode, MUIV_InputMode_RelVerify,
MUIA_Background, MUII_ButtonBack,
MUIA_Font, MUIV_Font_Button,
MUIA_Text_Contents, text,
MUIA_Text_PreParse, (defbutton ? "\33c\33b" : "\33c"),
End;
}
if(button && ctlchar)
{
set(button,MUIA_ControlChar,(LONG)ctlchar);
}
return button;
}
/************************************************************************
** PreParseButtonText()
** Using a certain "underscore" character, this function scans the input
** text and generates two variants: one for pattern matching, without
** the underscore character(s), one for MUI, including formatting codes
** to set the font style to "underlined" for the one character following
** the first "underscore" and "boldface" for the default button.
** Returns the character to use for the button's MUIA_ControlChar or -1
** on failure
*************************************************************************/
static WORD PreParseButtonText(STRPTR text, UBYTE uscore, BOOL defbutton, STRPTR *PMatchText, STRPTR *PParseText)
{
ULONG slen;
WORD hichar=0;
slen = strlen(text)+1;
if((*PMatchText = AllocVecPooled(Config->mc_MemPool,slen)) &&
(*PParseText = AllocVecPooled(Config->mc_MemPool,slen+6)))
{
STRPTR s,t;
UBYTE c;
s = *PMatchText;
t = text;
do
{
c = *t++;
if(c != uscore) *s++ = c; // omit <underscore> characters
} while(c);
s = *PParseText;
t = text;
do
{
c = *t++;
if(c == uscore)
{
*s++ = 0x1b; // ESC
*s++ = 'u'; // underline
*s++ = hichar = *t++; // save underlined character
*s++ = 0x1b; // ESC
*s++ = 'n'; // normal
if(defbutton)
{
*s++ = 0x1b; // ESC
*s++ = 'b'; // boldface
}
do
{
c = *t++;
if(c != uscore) *s++ = c; // just omit further <underscore> characters
} while(c);
} else
{
*s++ = c;
}
} while(c);
hichar = tolower(hichar);
return hichar;
} else
{
if(PMatchText) FreeVecPooled(Config->mc_MemPool,PMatchText);
return -1;
}
}